
#include "../idlib/precompiled.h"
#include "OSCDispatcher.h"
#include "Game_local.h"
#include "Camera.h"



#ifndef WIN32
static void* ThreadFunc( void* obj )
#else
static DWORD WINAPI ThreadFunc( LPVOID obj )
#endif
{
	static_cast<OSCDispatcher*>(obj)->mux_.Run();
	return 0;
};


OSCDispatcher::OSCDispatcher()
{
	socket = new UdpReceiveSocket(IpEndpointName(3333));
	mux_.AttachSocketListener(socket, this);
	locked = false;
	start();
}

OSCDispatcher::~OSCDispatcher(void)
{
	stop();
}



 void OSCDispatcher::ProcessBundle(const ReceivedBundle& b, const IpEndpointName& remoteEndpoint)
 {
 	for (ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i)
 	{
 		if (i->IsBundle())
 			ProcessBundle(ReceivedBundle(*i), remoteEndpoint);
 		else
 			ProcessMessage(ReceivedMessage(*i), remoteEndpoint);
 	}
 }




void OSCDispatcher::ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) {
	ReceivedPacket p( data, size );
	if(p.IsBundle()) {
		ProcessBundle(ReceivedBundle(p), remoteEndpoint);
	} else { 
		ProcessMessage(ReceivedMessage(p), remoteEndpoint);
	}
}




void OSCDispatcher::ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint )
    {
		idEntity	*ent;
        try{
			if( strcmp( m.AddressPattern(), "/tuio/2Dobj" ) == 0 ){
				osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
				const char *command = (arg++)->AsString();

				if (strcmp(command, "set") == 0) {
					for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
						if (ent->IsType(idTrigger_NuPlayReactable::GetClassType())) {
							idTrigger_NuPlayReactable* trigger;
							trigger = static_cast<idTrigger_NuPlayReactable*>( ent );
								trigger->SetParamsForScriptPre(arg);
								if (trigger->spawnArgs.GetString("reactvision_tag_nr", "1") == trigger->spawnArgs.GetString("id")) {							
									trigger->SetParamsForScriptPost(arg); 
									trigger->TriggerAction();
								}	
								arg = m.ArgumentsBegin();
								arg++;
						}
					}
				}
				//
				if (strcmp(command, "del") == 0) {
					//	gameLocal.Printf("del");
					for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
						if (ent->IsType(idTrigger_NuPlayReactable::GetClassType())) {
							idTrigger_NuPlayReactable* trigger;
							trigger = static_cast<idTrigger_NuPlayReactable*>( ent );
								trigger->SetParamsForScriptPre(arg);
								trigger->spawnArgs.SetInt("id", -1 * trigger->spawnArgs.GetInt("id"));
							//	gameLocal.Printf("set id = %d", trigger->spawnArgs.GetInt("id"));
								if (trigger->spawnArgs.GetString("reactvision_tag_nr", "1") == trigger->spawnArgs.GetString("id")) {							
									//trigger->SetParamsForScriptPost(arg); 
									
									trigger->TriggerAction();
								}	
								arg = m.ArgumentsBegin();
								arg++;
						}
					}
				}

			} else if ((strstr(m.AddressPattern(), "/nuplay") != NULL)) {
				osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
				const char *profile = (arg++)->AsString();
				for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
					if (strcmp(profile, "midi") == 0) {
						if (ent->IsType(idTrigger_NuPlayMidi::GetClassType())) {
							idTrigger_NuPlayMidi* trigger;
							trigger = static_cast<idTrigger_NuPlayMidi*>( ent );
							idStr channel = "/nuplay/channel_";
							channel.Append(trigger->spawnArgs.GetString("channel", "1"));
							//gameLocal.Printf(channel.c_str());
							//gameLocal.Printf("- %s -", m.AddressPattern());
				

							if (strcmp(channel.c_str(), m.AddressPattern()) == 0) {
								trigger->SetParamsForScriptPre(arg);
							//			gameLocal.Printf(trigger->spawnArgs.GetString("midi_message_trigger", "note_on"));
							//gameLocal.Printf(trigger->spawnArgs.GetString("midi_type"));

								if (trigger->spawnArgs.GetString("midi_message_trigger", "note_on") == trigger->spawnArgs.GetString("midi_type")) {		
									if (trigger->spawnArgs.GetString("midi_message_note_cc_number", "0") == trigger->spawnArgs.GetString("midi_param1")) {
									//	gameLocal.Printf("NOTE");
										trigger->SetParamsForScriptPost(arg); 
										trigger->TriggerAction();
									} else if (trigger->spawnArgs.GetString("midi_message_note_cc_number", "0") == trigger->spawnArgs.GetString("midi_message")) {
									//	gameLocal.Printf("SYSEX");
										trigger->SetParamsForScriptPost(arg); 
										trigger->TriggerAction();
									}
								}
								arg = m.ArgumentsBegin();
								arg++;
							}
						}
					}
					if (strcmp(profile, "audio") == 0) {
						if (ent->IsType(idTrigger_NuPlayLipSync::GetClassType())) {
							idTrigger_NuPlayLipSync* trigger;
							trigger = static_cast<idTrigger_NuPlayLipSync*>( ent );
							idStr channel = "/nuplay/channel_";
							channel.Append(trigger->spawnArgs.GetString("channel", "1"));
							if (strcmp(channel.c_str(), m.AddressPattern()) == 0) {
								trigger->SetParamsForScript(arg); 
								if (trigger->spawnArgs.GetString("audio_trigger", "1") == trigger->spawnArgs.GetString("threshold")) {							
									trigger->TriggerAction();
								}
							}
						}
					}
					if (strcmp(profile, "wiimote") == 0) {
						if (ent->IsType(idTrigger_NuPlayWiiMote::GetClassType())) {
							idTrigger_NuPlayWiiMote* trigger;

							trigger = static_cast<idTrigger_NuPlayWiiMote*>( ent );
							idStr channel = "/nuplay/channel_";
							channel.Append(trigger->spawnArgs.GetString("channel", "1"));
							if (strcmp(channel.c_str(), m.AddressPattern()) == 0) {
								trigger->SetParamsForScriptPre(arg);	
								if (strcmp(trigger->spawnArgs.GetString("wiimote_button_trigger", "button_A"),"always") == 0) {
										trigger->SetParamsForScriptPost(arg);
									trigger->TriggerAction();
								} else if (trigger->spawnArgs.GetInt(trigger->spawnArgs.GetString("wiimote_button_trigger", "button_A"))) {							
										trigger->SetParamsForScriptPost(arg);
										trigger->TriggerAction();
								}
									arg = m.ArgumentsBegin();
									arg++;
							}
						}
					} 

			
				}
			}
        }catch( osc::Exception& e ){
			gameLocal.Printf("error %s \n", e.what());
        } 

    }

void OSCDispatcher::setGUI(idUserInterface *gui) {
	_mainmenu_gui = gui;
}

void OSCDispatcher::start(bool lk) {
	locked = lk;
	if (!locked) {
		#ifndef WIN32
		pthread_create(&thread , NULL, ThreadFunc, this);
		#else
		DWORD threadId;
		thread = CreateThread( 0, 0, ThreadFunc, this, 0, &threadId );
		#endif
	} else mux_.Run();
}

void OSCDispatcher::stop() {
	mux_.Break();
	if (!locked) {
		#ifdef WIN32
		if( thread ) CloseHandle( thread );
		#endif
		thread = 0;
		locked = false;
	}
}